#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
import json
import requests
import subprocess
import sys
import argparse
import csv

CURRENT_DIR_ABSPATH = os.path.abspath(os.getcwd())

#读取json
def read_json_file(input_file: str) -> dict:
    if not os.path.isfile(input_file):
        raise OHOSException(f'{input_file} not found', '0008')

    with open(input_file, 'rb') as input_f:
        data = json.load(input_f)
        return data

def get_tdd_build_target(build_target_arg):
        parts_file = os.path.join(CURRENT_OHOS_ROOT, 'test/testfwk/developer_test/precise_compilation/part_tdd.json')
        tdd_manifest_file = os.path.join(CURRENT_OHOS_ROOT, '.repo/manifests/matrix_product.csv')
        parts_data = read_json_file(parts_file)
        repository_set = get_tdd_repository(tdd_manifest_file)
        prefix = 'out/rk3568/build_configs/'
        build_targets = []
        for target in target_name.split(','):
            if target not in repository_set:
                print('{} not find in csv!'.format(target))
                continue
            for item in parts_data:
                if item['name'] == target:
                    new_targets = [prefix + test_target for test_target in item['buildTarget'].split(',')]
                    build_targets.extend(new_targets)
                    break
            #else:
            #    build_targets = ['build/ohos/packages:build_all_test_pkg']
            #    target_generator = build_module.target_generator
            #    target_generator.regist_arg('use_thin_lto', False)
            #    break
        return build_targets

def get_export_project(export_key):
    if export_key != 'project_list':
        print(f"Unsupported export key: {export_key}. Expected 'project_list'.")
        return []

    export_button = os.getenv(export_key)
    if not export_button or export_button.strip() == '':
        print(f"The environment variable {export_key} is not set or is empty.")
        return []

    return [item.strip() for item in export_button.split(',')]

def get_export_files(export):
    if export == 'PR_FILE_PATHS':
        export_button = os.getenv(export)
        if not export_button:
            print('The environment variable PR_FILE_PATHS is not set')
            return None
        return export_button
    else:
        print(f"Unsupported export type: {export}")
        return None

def api_mkdir(param):
    post_url = "http://ci.openharmony.cn/api/sple/external/artifact/repo?projectName=openharmony"
    fails = 0
    while True:
        try:
            if fails >= 5:
                print("The number of failed requests is excessive")
                break
            headers = {'Content-Type': 'application/json'}
            ret = requests.post(post_url, data=json.dumps(param), headers=headers, timeout=10)
            if ret.status_code == 200:
                try:
                    mkdir_text = json.loads(ret.text)
                    print("The request was successful:", mkdir_text)
                    return mkdir_text
                except json.JSONDecodeError:
                    print("The response is not in valid JSON format.")
            else:
                print(f"The request failed, and the status code is displayed: {ret.status_code}, message: {ret.text}")
            fails += 1
        except requests.RequestException as e:
            print(f"Request Exception: {e}")
            fails += 1


def get_parts_deps(call):
    try:
        if call == "deps":
            subprocess.run(['./build.sh', '--product-name', 'rk3568', '--build-only-load'],
                           check=True, capture_output=True, text=True)
            file_path = os.path.join(CURRENT_DIR_ABSPATH, 'out', 'rk3568', 'build_configs', 'parts_info',
                                     'parts_deps.json')
            with open(file_path, 'r') as json_file:
                parts = json.load(json_file)
            return parts
        else:
            subprocess.run(['./build.sh', '--product-name', 'rk3568', '--build-only-gn'],
                           check=True, capture_output=True, text=True)
            file_path = os.path.join(CURRENT_DIR_ABSPATH, 'out', 'rk3568', 'build_configs', 'parts_info',
                                     'parts_info.json')
            with open(file_path, 'r') as json_file:
                parts = json.load(json_file)
            return parts
    except subprocess.CalledProcessError as e:
        print(f"Error occurred during subprocess execution: {e}")
        print(e.stderr)
        return None
    except FileNotFoundError:
        print("The JSON file was not found.")
        return None
    except json.JSONDecodeError:
        print("Failed to decode JSON.")
        return None


def path_innerapi(component):
    try:
        with open('out/rk3568/build_configs/parts_info/parts_info.json', 'r') as json_file:
            parts_data = json.load(json_file)
    except FileNotFoundError:
        return ['file not found']
    except json.JSONDecodeError:
        return ['json decode error']

    if component not in parts_data:
        return ['component not found']

    if component in parts_data and isinstance(parts_data[component], list):
        subsystem_name = [item['subsystem_name'] for item in parts_data[component] if 'subsystem_name' in item]
        origin_part_name = [item['origin_part_name'] for item in parts_data[component] if 'origin_part_name' in item]

    if subsystem_name and origin_part_name:
        file_path = os.path.join(CURRENT_DIR_ABSPATH, 'out', 'rk3568', subsystem_name[0], origin_part_name[0],
                                 'publicinfo')
        if os.path.isdir(file_path):
            innerapi_path = []
            for filename in os.listdir(file_path):
                if filename.endswith(".json"):
                    print(f"find innerapi file: {filename}")
                    with open(os.path.join(file_path, filename), "r") as f:
                        innerapi_json = json.load(f)
                    for public_config in innerapi_json.get('public_configs', []):
                        include_dirs = public_config.get('include_dirs', [])
                        innerapi_path.extend(include_dirs)
            path_set = list(set(innerapi_path))
            print("+++++++++++++++++++++++++++++++=")
            print("innerapi:")
            print(component)
            print(path_set)
            print("+++++++++++++++++++++++++++++++=")
            return path_set
        else:
            print("+++++++++++++++++++++++++++++++=")
            print("innerapi:")
            print(component)
            print('noinnerapi')
            print("+++++++++++++++++++++++++++++++=")
            return ['noinnerapi']
    else:
        return ['no subsystem or origin part found']


def bool_only_build(house, export_button):
    deps_files = json.loads(export_button)
    deps_value = deps_files.get(house, [])
    api_bool = False
    for file in deps_value:
        ext = os.path.splitext(file)[1].lower()
        if ext in ['.hpp', '.inl', '.inc', '.h', '.in']:
            print(f"{file} ends with a valid extension: {ext}")
            api_bool = True
            break
        else:
            print(f"{file} does not end with a valid extension.")
    return api_bool


def file_paths(component, house, export_button):
    try:
        with open('out/rk3568/build_configs/parts_info/parts_path_info.json', 'r') as json_file:
            parts_data = json.load(json_file)
    except FileNotFoundError:
        return ['file not found']
    except json.JSONDecodeError:
        return ['json decode error']
    component_mkdir = parts_data[component]
    deps_files = json.loads(export_button)
    deps_value = deps_files.get(house, [])
    files_path = [f'{component_mkdir}/{file}' for file in deps_value]
    return files_path


def bool_target_build(house, component):
    export_button = get_export_files('PR_FILE_PATHS')
    if not bool_only_build(house, export_button):
        return True
    innerapi_paths = path_innerapi(component)
    if len(innerapi_paths) == 0 or innerapi_paths[0] == 'noinnerapi':
        return True
    file_paths_list = file_paths(component, house, export_button)
    for file_path in file_paths_list:
        for innerapi_path in innerapi_paths:
            if innerapi_path.startswith('//'):
                innerapi_path = innerapi_path[2:]
            if file_path.startswith(innerapi_path):
                return False
    return True


def get_build_target(deps):
    build_target = ' --build-target '
    if not deps:
        return ' --build-target make_all '
    targets = ''
    for dep in deps:
        targets += build_target + dep
    return targets

def get_tdd_repository(input_file):
    if not os.path.isfile(input_file):
        raise OHOSException(f'{input_file} not found')
    target_set = set()
    with open(input_file, 'r') as input_f:
        data = csv.DictReader(input_f)
        for csv_row in data:
            if csv_row.get('dayu200_tdd') == 'Y':
                target_set.add(csv_row['repoistory'])
    return target_set

def get_test_target(deps):
    ret = '--build-target'
    if not deps:
        return '--build-target build/ohos/packages:build_all_test_pkg'
    for dep in deps:
        ret += ' ' + dep
    return ret


def get_component_sole_target(component, parts_data, repository_set):
    prefix = 'out/rk3568/build_configs/'
    build_targets = []
    for item in parts_data:
        if item['parts'] == component:
            if item['name'] not in repository_set:
                print('{} not find in csv!'.format(component))
                return None
            new_targets = [prefix + item['buildTarget'].split(',')[0]]
            build_targets.extend(new_targets)
            break
    return build_targets

def get_component_all_target(component, parts_data, repository_set):
    prefix = 'out/rk3568/build_configs/'
    build_targets = []
    for item in parts_data:
        if item['parts'] == component:
            if item['name'] not in repository_set:
                print('{} not find in csv!'.format(component))
                return None
            new_targets = [prefix + test_target for test_target in item['buildTarget'].split(',')]
            build_targets.extend(new_targets)
            break
    return build_targets

def build_all_tdd(args):
    build_cmd = ['./build.sh', '--product-name', 'rk3568', '--build-target build/ohos/packages:build_all_test_pkg', args.gnargs]
    try:
        result = subprocess.run(build_cmd, check=True, capture_output=True, text=True)
        print(result.stdout)
        return 0
    except subprocess.CalledProcessError as e:
        print(f"Build failed with error: {e.stderr}")
        return 1


def main():
    parts_file = os.path.join(CURRENT_DIR_ABSPATH, 'test/testfwk/developer_test/precise_compilation/part_tdd.json')
    tdd_manifest_file = os.path.join(CURRENT_DIR_ABSPATH, '.repo/manifests/matrix_product.csv')
    parts_data = read_json_file(parts_file)
    repository_set = get_tdd_repository(tdd_manifest_file)
    prefix = 'out/rk3568/build_configs/'
    build_targets = []

    parser = argparse.ArgumentParser()
    parser.add_argument('--gnargs', required=True)
    args = parser.parse_args()

    project_list = get_export_project('project_list')
    values_to_all = {'manifest'}
    if not project_list or any(value in project_list for value in values_to_all):
        build_cmd = ['./build.sh', '--product-name', 'rk3568', '--build-target build/ohos/packages:build_all_test_pkg', args.gnargs]
        try:
            result = subprocess.run(build_cmd, check=True, capture_output=True, text=True)
            print(result.stdout)
            return 0
        except subprocess.CalledProcessError as e:
            print(f"Build failed with error: {e.stderr}")
            return 1

    parts_deps = get_parts_deps("deps")
    component_dir = api_mkdir(project_list)

    component_dep_list = []
    for part_house, part in component_dir.items():
        if part and part.keys():
            component_name = list(part.keys())[0]
            component_dep_list.append(component_name)
            print("+++++++++++++++++++++++++++++++=")
            print("part:")
            print(component_name)
            print(part_house)
            print("+++++++++++++++++++++++++++++++=")
            if bool_target_build(part_house, component_name):
                build_targets.extend(get_component_sole_target(component_name, parts_data, repository_set))
                print("基尼台妹")
                continue
            else:
                print("再多一眼看一眼就会爆炸")
                build_targets.extend(get_component_all_target(component_name, parts_data, repository_set))
                #for c, info in parts_deps.items():
                #    if info:
                #        if (info.get("components") and component_name in info.get("components")) or (
                #                info.get("third_party") and component_name in info.get("third_party")):
                #            component_dep_list.append(c)
        else:
            return build_all_tdd(args)
    component_dep_list = list(set(component_dep_list))
    if build_targets == []:
        return build_all_tdd(args)
    print("+++++++++++++++++++++++++++++++=")
    print("targets:")
    print(build_targets)
    print("+++++++++++++++++++++++++++++++=")
    # build_targets = list(set(build_targets))
    print("+++++++++++++++++++++++++++++++=")
    print("targets:")
    print(build_targets)
    print("+++++++++++++++++++++++++++++++=")
    targets = get_test_target(build_targets)
    print("+++++++++++++++++++++++++++++++=")
    print("build target:")
    print(targets)
    print("+++++++++++++++++++++++++++++++=")
    build_cmd = ['./build.sh', '--product-name', 'rk3568', targets, args.gnargs]
    try:
        result = subprocess.run(build_cmd, check=True, capture_output=True, text=True)
        print(result.stdout)
    except subprocess.CalledProcessError as e:
        print(f"Build failed with error: {e.stderr}")


if __name__ == '__main__':
    sys.exit(main())
